/**
 * 
 */
package br.com.ac.fatureweb.view;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

import javax.faces.event.ActionEvent;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.Part;

import org.apache.commons.io.IOUtils;
import org.primefaces.json.JSONException;

import br.com.ac.fatureweb.jf.model.Aviso_Debito;
import br.com.ac.fatureweb.jf.model.Calculo;
import br.com.ac.fatureweb.jf.model.Configuracao;
import br.com.ac.fatureweb.jf.model.Debitos;
import br.com.ac.fatureweb.jf.model.Economias;
import br.com.ac.fatureweb.jf.model.EnumTypeCarga;
import br.com.ac.fatureweb.jf.model.Ficha;
import br.com.ac.fatureweb.jf.model.Historico;
import br.com.ac.fatureweb.jf.model.Leiturista;
import br.com.ac.fatureweb.jf.model.Mensagem;
import br.com.ac.fatureweb.jf.model.Ocorrencia;
import br.com.ac.fatureweb.jf.model.Reservatorio;
import br.com.ac.fatureweb.jf.model.Saldo;
import br.com.ac.fatureweb.jf.model.Servicos_cobrar;
import br.com.ac.fatureweb.jf.model.Tarifa;
import br.com.ac.fatureweb.jf.model.Tarifa_social;
import br.com.ac.fatureweb.model.Carga;
import br.com.ac.fatureweb.service.NgcImportacaoBean;
import br.com.ac.fatureweb.utilitary.FacesUtils;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

/**
 * @author aldivone
 *
 */
@Named
@ViewScoped
public class ImportacaoBean implements Serializable {

	private static final long serialVersionUID = -2254926457921530336L;

	private String url = "";

	private Part arquivo = null;

	private StringBuilder conteudoArquivo = null;

	@Inject
	private NgcImportacaoBean ngcImportacaoBean;

	/**
	 * 
	 * @return
	 * @throws IOException
	 */
	public String carregarArquivo() throws IOException {

		if (arquivo == null) {
			FacesUtils.addMessageError("Arquivo para carga não foi informado!");
			return null;
		}

		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		InputStream inputStream = null;

		try {
			inputStream = arquivo.getInputStream();

			int read = 0;

			final byte[] bytes = new byte[1024];

			while ((read = inputStream.read(bytes)) != -1) {
				outputStream.write(bytes, 0, read);
			}

			conteudoArquivo = new StringBuilder(outputStream.toString("UTF-8"));

			FacesUtils.addMessageInformation("Arquivo carregado com sucesso!");

		} catch (IOException e) {

		} finally {
			if (outputStream != null) {
				outputStream.close();
			}
			if (inputStream != null) {
				inputStream.close();
			}
		}
		return null;
	}

	/**
	 * 
	 * @param event
	 */
	public void importarArquivo(ActionEvent event) {
		try {

			if (conteudoArquivo == null || conteudoArquivo.length() < 0) {
				FacesUtils.addMessageError("Arquivo para"
						+ " processamento não foi carregado.");
			}

			Gson gson = new Gson();
			

			JsonObject fromJson = gson.fromJson(conteudoArquivo.toString(),
					JsonObject.class);

			Carga carga = importarJson(gson, fromJson);

			FacesUtils.addMessageInformation("Importado: "
					+ carga.getQtdImovel() + " imóveis e "
					+ carga.getQtdLancamentoFuturo() + " Lançamento futuros.");

			arquivo = null;
			conteudoArquivo = null;
		} catch (Exception ex) {
			arquivo = null;
			conteudoArquivo = null;
			FacesUtils.addMessageError("Erro no processamento da carga.");
			ex.printStackTrace();
		}
	}

	/**
	 * @return the arquivo
	 */
	public Part getArquivo() {
		return arquivo;
	}

	/**
	 * @param arquivo
	 *            the arquivo to set
	 */
	public void setArquivo(Part arquivo) {
		this.arquivo = arquivo;
	}

	/**
	 * 
	 * @param event
	 */
	public void importar(ActionEvent event) {
		try {
			if (url == null) {
				FacesUtils
						.addMessageError("Arquivo para carga não foi informado!");
				return;
			}

			Gson gson = new Gson();

			JsonObject fromJson = gson.fromJson(readJsonFromUrl(url),
					JsonObject.class);

			if (fromJson == null) {
				FacesUtils
						.addMessageWarning("Não há faturamento disponível para carga.");
				return;
			}

			Carga carga = importarJson(gson, fromJson);

			FacesUtils.addMessageInformation("Importado: "
					+ carga.getQtdImovel() + " imóveis e "
					+ carga.getQtdLancamentoFuturo() + " Lançamento futuros.");

		} catch (Exception ex) {
			FacesUtils.addMessageError("Erro no processamento da carga.");
			ex.printStackTrace();
		}
	}

	private Carga importarJson(Gson gson, JsonObject fromJson) {
		Set<Entry<String, JsonElement>> entrySet = fromJson.entrySet();

		Calculo configCalculoSaae = null;
		Configuracao configuracaoSaae = null;
		List<Aviso_Debito> lstAvisoDebito = null;
		List<Debitos> lstDebito = null;
		List<Economias> lstEconomia = null;
		List<Ficha> lstImovel = null;
		List<Historico> lstHistorico = null;
		List<Leiturista> lstLeiturista = null;
		List<Mensagem> lstMensagem = null;
		List<Ocorrencia> lstOcorrencia = null;
		List<Reservatorio> lstReservatorio = null;
		List<Saldo> lstSaldoDebitoCredito = null;
		List<Servicos_cobrar> lstLancamentoFuturo = null;
		List<Tarifa_social> lstTarifaSocial = null;
		List<Tarifa> lstTarifa = null;

		for (Entry<String, JsonElement> entry : entrySet) {
			String key = entry.getKey();

			EnumTypeCarga enumTypeCarga = EnumTypeCarga.valueOF(key);

			switch (enumTypeCarga) {
			case CALCULO: {
				configCalculoSaae = gson.fromJson(entry.getValue(),
						Calculo.class);
				break;
			}
			case CONFIGURACAO: {
				configuracaoSaae = gson.fromJson(entry.getValue(),
						Configuracao.class);
				break;
			}
			case AVISO_DEBITO: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Aviso_Debito>>() {
				}.getType();
				lstAvisoDebito = gson.fromJson(entry.getValue(), type);
				break;
			}
			case DEBITOS: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Debitos>>() {
				}.getType();
				lstDebito = gson.fromJson(entry.getValue(), type);
				break;
			}
			case ECONOMIAS: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Economias>>() {
				}.getType();
				lstEconomia = gson.fromJson(entry.getValue(), type);
				break;
			}
			case FICHA: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Ficha>>() {
				}.getType();
				lstImovel = gson.fromJson(entry.getValue(), type);
				break;
			}
			case HISTORICO: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Historico>>() {
				}.getType();
				lstHistorico = gson.fromJson(entry.getValue(), type);
				break;
			}
			case LEITURISTA: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Leiturista>>() {
				}.getType();
				lstLeiturista = gson.fromJson(entry.getValue(), type);
				break;
			}
			case MENSAGEM: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Mensagem>>() {
				}.getType();
				lstMensagem = gson.fromJson(entry.getValue(), type);
				break;
			}
			case OCORRENCIA: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Ocorrencia>>() {
				}.getType();
				lstOcorrencia = gson.fromJson(entry.getValue(), type);
				break;
			}
			case RESERVATORIO: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Reservatorio>>() {
				}.getType();
				lstReservatorio = gson.fromJson(entry.getValue(), type);
				break;
			}
			case SALDO: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Saldo>>() {
				}.getType();
				lstSaldoDebitoCredito = gson.fromJson(entry.getValue(), type);
				break;
			}
			case SERVICOS_COBRAR: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Servicos_cobrar>>() {
				}.getType();
				lstLancamentoFuturo = gson.fromJson(entry.getValue(), type);
				break;
			}
			case TARIFA: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Tarifa>>() {
				}.getType();
				lstTarifa = gson.fromJson(entry.getValue(), type);
				break;
			}
			case TARIFA_SOCIAL: {
				Type type = new com.google.gson.reflect.TypeToken<ArrayList<Tarifa_social>>() {
				}.getType();
				lstTarifaSocial = gson.fromJson(entry.getValue(), type);
				break;
			}
			}
		}

		Carga carga = ngcImportacaoBean.importar(configCalculoSaae,
				configuracaoSaae, lstAvisoDebito, lstDebito, lstEconomia,
				lstImovel, lstHistorico, lstLeiturista, lstMensagem,
				lstOcorrencia, lstReservatorio, lstSaldoDebitoCredito,
				lstLancamentoFuturo, lstTarifaSocial, lstTarifa);
		return carga;
	}

	/**
	 * 
	 * @param url
	 * @return
	 * @throws IOException
	 * @throws JSONException
	 */
	public static String readJsonFromUrl(String url) throws IOException,
			JSONException {

		InputStream is = new URL(url).openStream();

		try {
			return IOUtils.toString(new BufferedReader(new InputStreamReader(
					is, Charset.forName("UTF-8"))));
		} finally {
			is.close();
		}
	}

	/**
	 * @return the url
	 */
	public String getUrl() {
		return url;
	}

	/**
	 * @param url
	 *            the url to set
	 */
	public void setUrl(String url) {
		this.url = url;
	}
}